package com.mjf.ys.util;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.fasterxml.jackson.core.type.TypeReference;
import com.mjf.ys.config.YsConfig;
import com.mjf.ys.enums.YSApiEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.*;

/**
 * <p>
 * desc
 * </p>
 *
 * @author chenshoumeng
 * @date 2025/6/7 23:36
 */
@Slf4j
@Component
public class YSSendUtil {


    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private YsConfig ysConfig;

    /**
     * 请求接口 -post请求 - Urlencoded格式参数
     *
     * @return Map 参数
     */
    public String reqForRespByUrlencoded(String url, MultiValueMap<String, String> param) {
        String reqForResp;
        try {
            // REST HTTP HEADER
            HttpHeaders httpHeaders = new HttpHeaders();
            httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
            //rest http entity
            HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(param, httpHeaders);
            reqForResp = restTemplate.postForObject(url, request, String.class);
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
        return reqForResp;
    }

    /**
     * 请求接口 -post请求- json格式参数
     *
     * @param url   url
     * @param param param
     * @return Map
     */
    public String reqForResp(String url, Map<String, Object> param) {
        String reqForResp;
        try {
            // REST HTTP HEADER
            HttpHeaders httpHeaders = new HttpHeaders();
            httpHeaders.setContentType(MediaType.APPLICATION_JSON);
            //rest http entity
            HttpEntity<Map<String, Object>> request = new HttpEntity<>(param, httpHeaders);
            reqForResp = restTemplate.postForObject(url, request, String.class);
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
        return reqForResp;
    }

    /**
     * get请求-携带参数
     *
     * @param url   url
     * @param param param
     * @return Map
     */
    public String reqForGetWithParam(String url, MultiValueMap<String, String> param) {
        String reqForResp;
        try {
            UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url).queryParams(param);
            String ussss = builder.toUriString();
            reqForResp = restTemplate.getForObject(ussss, String.class);
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
        return reqForResp;
    }

    /**
     * get请求-不携带参数
     *
     * @param url  url
     * @return Map
     */
    public String reqForGetWithOutParam(String url) {
        String reqForResp;
        try {
            reqForResp = restTemplate.getForObject(url, String.class);
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
        return reqForResp;
    }

    /**
     * 获取动态域名
     *
     * @param url url
     * @return String
     */
    private DnsResVo.ResData getDdns(String url) {
        String repsp = reqForGetWithOutParam(url);

        // 解析接口
        DnsResVo dnsResult = JSON.parseObject(repsp, DnsResVo.class);
        if (Objects.isNull(dnsResult) || !"00000".equals(dnsResult.getCode())) {
            log.error("获取动态域名失败，接口返回结果：{}", JSON.toJSONString(dnsResult));
            throw new RuntimeException("获取YouBip动态域名失败,请联系管理员！");
        }
        return dnsResult.getData();
    }

    /**
     * 获取动态地址
     * @param ysApiEnum
     * @return
     */
    public String getSendUrl(YSApiEnum ysApiEnum) {
        // 获取YouBip动态域名
        String dnsRequerturl =
            ysConfig.getIpAddr() + YSApiEnum.YS_API_DYNAMIC_DOMAIN_URL.getUrl() + ysConfig.getTenantId();
        DnsResVo.ResData dnsResData = getDdns(dnsRequerturl);
        // 获取access_token
        String requestUrl = dnsResData.getTokenUrl() + YSApiEnum.YS_API_GET_ACCESS_TOKEN_URL.getUrl();
        AccessTokenResponse accessTokenResponse = getAccessTokenResponse(requestUrl, ysConfig.getAppKey(), ysConfig.getAppSecret());
        return dnsResData.getGatewayUrl() + ysApiEnum.getUrl() + "?access_token="+ accessTokenResponse.getAccessToken();
    }

    /**
     * 获取AccessToken
     *
     * @param requestUrl requestUrl
     * @param appKey     appKey
     * @param appSecret  appSecret
     * @return AccessTokenResponse
     */
    public static AccessTokenResponse getAccessTokenResponse(String requestUrl, String appKey, String appSecret) {
        // 请求
        GenericResponse<AccessTokenResponse> response = null;
        try {
            Map<String, String> params = new HashMap<>();
            // 除签名外的其他参数
            params.put("appKey", appKey);
            params.put("timestamp", String.valueOf(System.currentTimeMillis()));
            // 计算签名
            String signature = sign(params, appSecret);
            params.put("signature", signature);
            response = RequestTool.doGet(requestUrl, params, new TypeReference<GenericResponse<AccessTokenResponse>>() {
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (!Objects.isNull(response) && response.isSuccess() && StrUtil.isNotBlank(response.getData().getAccessToken())) {
            return response.getData();
        }
        log.error("请求开放平台接口失败，code: {}, message: {}", response.getCode(), response.getMessage());
        throw new RuntimeException("获取YouBip鉴权access_token失败,请联系管理员！");
    }

    /**
     * 加签方法
     *
     * @param params    appKey和timestamp信息
     * @param appSecret API调用里对应的secret
     * @return 返回加签信息
     */
    public static String sign(Map<String, String> params, String appSecret) {
        StringBuilder stringBuilder = new StringBuilder();
        for (Map.Entry<String, String> entry : params.entrySet()) {
            stringBuilder.append(entry.getKey()).append(entry.getValue());
        }
        Mac mac;
        String res = null;
        try {
            mac = Mac.getInstance("HmacSHA256");
            mac.init(new SecretKeySpec(appSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
            byte[] signData = mac.doFinal(stringBuilder.toString().getBytes(StandardCharsets.UTF_8));
            String base64String = Base64.getEncoder().encodeToString(signData);
            res = URLEncoder.encode(base64String, "UTF-8");
        } catch (NoSuchAlgorithmException | InvalidKeyException | UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        return res;
    }

}
